#include "pch.h"
#include "LocalEdgeCollapseMeshSimplification.h"
using namespace AutomatedSurfaceReconstruction;

bool CLocalEdgeCollapseMeshSimplification::simplifyMesh()
{
	const std::size_t EdgeCountThreshold = m_ExpectedFacetNum * 1.5;
	CGAL::Surface_mesh_simplification::Count_stop_predicate<CGALMeshType> Stop(EdgeCountThreshold);
	CGAL::Surface_mesh_simplification::edge_collapse(m_Mesh, Stop);
	return true;
}

bool CLocalEdgeCollapseMeshSimplification::simplifyMeshLocally(const CGALPointSetType& vConstrainedPointSet)
{
	__getConstrainedPointIndex(vConstrainedPointSet);
	__specifyConstrainedEdges();
	__simplifyLocalMesh();

	return true;
}

bool CLocalEdgeCollapseMeshSimplification::__specifyConstrainedEdges()
{
	auto isContain = [&](const std::uint32_t vIndex)
	{
		for (auto it = m_ConstrainedVertexIndexSet.cbegin(); it != m_ConstrainedVertexIndexSet.cend(); it++)
			if (*it == vIndex)return true;
		return false;
	};

	CGAL::Unique_hash_map<EdgeDescriptor, bool> ConstrainMap(false);
	for (auto Edge : edges(m_Mesh))
	{
		HalfedgeDescriptor HalfEdge = halfedge(Edge, m_Mesh);
		if (isContain(source(HalfEdge, m_Mesh)) || isContain(target(HalfEdge, m_Mesh)))ConstrainMap[Edge] = true;
	}
	std::swap(m_ConstrainedEdges, ConstrainMap);

	return true;
}

bool CLocalEdgeCollapseMeshSimplification::__simplifyLocalMesh()
{
	namespace SMS = CGAL::Surface_mesh_simplification;
	SConstrainedEdgeMap ConstrainedEdgeMap(m_ConstrainedEdges);
	CGAL::Surface_mesh_simplification::Constrained_placement<CGAL::Surface_mesh_simplification::Midpoint_placement<CGALMeshType>, SConstrainedEdgeMap> Placement(ConstrainedEdgeMap);
	SMS::Count_stop_predicate<CGALMeshType> stop(m_ExpectedFacetNum*1.5);
	std::uint32_t RemoveEdgeNum = SMS::edge_collapse(m_Mesh, stop,
		CGAL::parameters::edge_is_constrained_map(ConstrainedEdgeMap)
		.get_placement(Placement));

	return true;
}

void CLocalEdgeCollapseMeshSimplification::__getConstrainedPointIndex(const CGALPointSetType& vConstrainedPointSet)
{
	std::set < Kernel::Point_3 > IsBelong2RoadBoundaryPoint;
	for (auto& ConstrainedPoint : vConstrainedPointSet)
	{
		IsBelong2RoadBoundaryPoint.emplace(vConstrainedPointSet.point(ConstrainedPoint));
	}

	std::vector<std::uint32_t> ConstrainedPointIndexSet;
	ConstrainedPointIndexSet.reserve(vConstrainedPointSet.size());

	for (auto VertexIter = m_Mesh.vertices_begin(); VertexIter != m_Mesh.vertices_end(); VertexIter++)
	{
		if (IsBelong2RoadBoundaryPoint.contains(Kernel::Point_3(m_Mesh.point(*VertexIter).x(), m_Mesh.point(*VertexIter).y(), m_Mesh.point(*VertexIter).z())))
			ConstrainedPointIndexSet.emplace_back(*VertexIter);
	}

	std::swap(m_ConstrainedVertexIndexSet, ConstrainedPointIndexSet);
}
